USB device driver questions

1. USB mouse works for a while then stop.

A: The USB device driver may not have the patch.
   - Ask customer to use smutilce and dump register values
   - Check register 0x00400010 value:
     0x80000032 is non-patched device driver's value, used for SYSTEM MEMORY
     0x80000036 is patched device driver's value, used for LOCAL VIDEO MEMORY
   - If they use the wrong device driver, then ask them use the correct one.

B: The interrupt handler may be wrong.
   - If customer's platform uses our video memory as the USB buffer, then they
     need add the dumy read instruction patch inside interrupt handler.
   - Ask customer to use smutilce and dump register values
   - Check register 0x0000002C (Interrupt Status) and 0x00000030 (Interrupt Mask) value:
     * if REG_0x30 bit 6 (USB host interrupt mask) is been turned off, then the customer's 
       interrupt handler didn't restore interrupt mask register's value after the interrupt
       handler process done.

     * if REG_0x30 bit 6 (USB host interrupt mask) is not been turned off and 
       REG_0x2c bit 6 (USB host interrupt status) is active, then the customer's 
       interrupt handler didn't process correctly.

2. Interrupt handler implementation for WinCE XScale.

   - \WINCE\PLATFORM\XScale\KERNEL\hal\cfwXsc1.c

	/* GLOBALS */
	DWORD dwSMIIntMask;

	void OEMInit()
	{
		...

		/* SMI, John Huang */
		// enable GPIO_1 Interrupt for SMI Voyager
		// rising edge triggered
		v_pGPIOReg->GRER_x |= GPIO_1; 	 
		GEDR_GPIO1_EDGE_CLR(v_pGPIOReg->GEDR_x);
		INTC_GPIO1_INT_EN (v_pICReg->icmr);

		...
	}

	BOOL OEMInterruptEnable ()
	{
		...

		case SYSINTR_SMIVGX_USB:
			// enable SMI USB Host Interrupt
			*(volatile DWORD *)(v_pSMIReg + 0x03E00030) |= 0x00000040;
			// save the current VGX interrupt enable mask register value.
			dwSMIIntMask = *(volatile DWORD *)(v_pSMIReg + 0x03E00030);

			break;
		...
	}

	void OEMInterruptDisable()
	{
		...

		case SYSINTR_SMIVGX_USB:
			// disable SMI USB Host Interrupt
			*(volatile ULONG *)(v_pSMIReg + 0x03E00030) &= ~0x00000040;

			break;
		...
	}

	void OEMInterruptDone()
	{
		...

		case SYSINTR_SMIVGX_USB:
			*(volatile ULONG *)(v_pSMIReg + 0x03E00030) = dwSMIIntMask;
			break;

		...
	}

   - \WINCE\PLATFORM\XScale\KERNEL\hal\arm\intxsc1.c
   
	/* SMI, John Huang */
	extern DWORD dwSMIIntMask;

	int OEMInterruptHandler(unsigned int ra)
	{
		...
		
		unsigned long usbsts;
		static volatile UCHAR	*v_pSMI;

		if (bInitializeMe)
		{
			... 
			/* SMI, John Huang */
			v_pSMI = (volatile UCHAR *) SMI_U_VIRTUAL;
			dwSMIIntMask = SMI_REG(v_pSMI + SMI_INTERRUPT_MASK_REG);
			....
		}
		....

A: Video Memory as the USB buffer and "DOES NEED PATCH".
	
		else if(ipreg_copy & INTC_GPIO1) 
		{
			//
			// SMI VoyagerGX interrupt 
			// mask interrupt & clear the edge detection
			//

			// clear GPIO_1 edge dection
			GEDR_GPIO1_EDGE_CLR(v_pGPIOReg->GEDR_x);

			// check if USB interrupt
			if (SMI_REG(v_pSMI + SMI_INTERRUPT_STATUS_REG) & SMI_INTERRUPT_MASK_USB)
			{
				// Dummy read, flush the VoyagerGX's cache
				// fix for USB host hang, 0x720000 just a dummy address
				*(volatile ULONG *)(v_pSMI + 0x00720000);
				// save USB host interrupt status
				usbsts = SMI_REG(v_pSMI + SMI_USB_INT_STATUS_REG);
				// mask SF interrupt, check for other interrupt
				usbsts &= ~0x00000004;
				// if other usb interrupts are triggered, 
				// then pass the interrupt into USB device driver to handle
				if (SMI_REG(v_pSMI + SMI_USB_INT_MASK_REG) & usbsts)
				{
					// save the current VGX interrupt enable mask register value.
					dwSMIIntMask = SMI_REG(v_pSMI + SMI_INTERRUPT_MASK_REG);

					// clear VGX interrupt, put mask back after 
					// device driver interrupt handler done
					SMI_REG(v_pSMI + SMI_INTERRUPT_MASK_REG) = 0;
	
					return SYSINTR_SMIVGX_USB;
				}
				// only SF interrupt, write back usb interrupt status to clear and do nothing
				SMI_REG(v_pSMI + SMI_USB_INT_STATUS_REG) = 0x00000004;
			}
			return SYSINTR_NOP;
		}

B: Video Memory as the USB buffer and "DOESN'T NEED PATCH".
		if(ipreg_copy & INTC_OSMR0) 
    		{
			...
			// Dummy read, flush the VoyagerGX's cache
			// fix for USB host hang, 0x720000 just a dummy address
			*(volatile ULONG *)(v_pSMI + 0x00700000);
			...
		}
		else if(ipreg_copy & INTC_GPIO1) 
		{
			//
			// SMI VoyagerGX interrupt 
			// mask interrupt & clear the edge detection
			//

			// clear GPIO_1 edge dection
			GEDR_GPIO1_EDGE_CLR(v_pGPIOReg->GEDR_x);

			// check if USB interrupt
			if (SMI_REG(v_pSMI + SMI_INTERRUPT_STATUS_REG) & SMI_INTERRUPT_MASK_USB)
			{
				*(volatile ULONG *)(v_pSMI + 0x00700000);

				// save the current VGX interrupt enable mask register value.
				dwSMIIntMask = SMI_REG(v_pSMI + SMI_INTERRUPT_MASK_REG);

				// clear VGX interrupt, put mask back after 
				// device driver interrupt handler done
				SMI_REG(v_pSMI + SMI_INTERRUPT_MASK_REG) = 0;

				return SYSINTR_SMIVGX_USB;
			}
			return SYSINTR_NOP;
		}

C: System Memory as the USB buffer and "DOESN'T NEED PATHC".
		else if(ipreg_copy & INTC_GPIO1) 
		{
			//
			// SMI VoyagerGX interrupt 
			// mask interrupt & clear the edge detection
			//

			// clear GPIO_1 edge dection
			GEDR_GPIO1_EDGE_CLR(v_pGPIOReg->GEDR_x);

			// check if USB interrupt
			if (SMI_REG(v_pSMI + SMI_INTERRUPT_STATUS_REG) & SMI_INTERRUPT_MASK_USB)
			{
				// save the current VGX interrupt enable mask register value.
				dwSMIIntMask = SMI_REG(v_pSMI + SMI_INTERRUPT_MASK_REG);

				// clear VGX interrupt, put mask back after 
				// device driver interrupt handler done
				SMI_REG(v_pSMI + SMI_INTERRUPT_MASK_REG) = 0;
	
				return SYSINTR_SMIVGX_USB;
			}
			return SYSINTR_NOP;
		}

	- CONFIG.BIB
		...
		AUD_DMA    84020000  0000A000  RESERVED
		SLEEP_SAV  8402a000  00001000  RESERVED
		DRV_GLB    8402b000  00001000  RESERVED
		UNUSED2    8402c000  00004000  RESERVED
	------->USB_BUF    84030000  00010000  RESERVED	; 64k for USB Host. OFFSET 0x30000
		DISPLAY    84040000  00400000  RESERVED	; 640(W)x480(H)x2(16bpp)x2(2 frame buffers)
		...

	- \WINCE\PLATFORM\XScale\inc\MemDefs.h
		...
		#define MEM_BASE_C_VIRTUAL		0x84000000
		#define EDBG_PHYSICAL_MEMORY_START	(MEM_BASE_C_VIRTUAL+CACHED_TO_UNCACHED_OFFSET+0x120000)      // Ethernet Debugger Pool Address
		#define MEM_BASE_C_VIRTUAL1		0x88000000
		#define MEM_BASE_C_VIRTUAL2		0x8C000000
		#define MEM_BASE_C_VIRTUAL3		0x90000000
		#define MEM_BASE_C_VIRTUAL_END		0x94000000

		#define MEM_BASE_U_VIRTUAL		(MEM_BASE_C_VIRTUAL+CACHED_TO_UNCACHED_OFFSET)


		#define AUDIO_DMA_OFFSET		(0x00020000)
		//#define DISPLAY_DMA_OFFSET		(0x01C00000)
		#define DISPLAY_DMA_OFFSET		(0x00040000)
	------->#define USB_BUFFER_OFFSET		(0x00030000)
		#define SLEEP_SAVE_OFFSET		(0x0002a000)
		#define DRIVER_GLOBALS_OFFSET		(0x0002b000)
		...

	------->#define USB_BUFFER_SIZE			(0x10000)

	------->#define USB_BUFFER_BASE_PHYSICAL	(MEM_BASE_PHYSICAL+USB_BUFFER_OFFSET)
	------->#define USB_BUFFER_BASE_C_VIRTUAL	(MEM_BASE_C_VIRTUAL+USB_BUFFER_OFFSET)
	------->#define USB_BUFFER_BASE_U_VIRTUAL	(USB_BUFFER_BASE_C_VIRTUAL+CACHED_TO_UNCACHED_OFFSET)

3. Registry Setting for WinCE

A: PCI
	IF BSP_USB_SMIVGX
	[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SMIVGXUSB]
	   "Prefix"="HCD"
	   "Dll"="vgx_ohci.dll"
	   "ProgIF"=dword:10
	   "IsrDll"="giisr.dll"
	   "IsrHandler"="ISRHandler"
	ENDIF

B: VYTEK XScale (64k buffer in Video memory)
	IF BSP_USB_SMIVGX
	[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SMIVGXUSB]
	   "Prefix"="HCD"
	   "Dll"="vgx_ohci.dll"
	   "Irq"=dword:24
	   "SysIntr"=dword:24
	   "MemBase"=dword:107F0000 ; CS + 0x007F0000 the bottom 64K of video memory
	   "RegBase"=dword:13E00000	; CS + 0x03E00000
	ENDIF

C: VYTEK XScale (64k buffer in system memory)
	IF BSP_USB_SMIVGX
	[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SMIVGXUSB]
	   "Prefix"="HCD"
	   "Dll"="vgx_ohci.dll"
	   "Irq"=dword:24
	   "SysIntr"=dword:24
	   "UMA" = dword:1
	   "UMAOffset"= dword:30000 ; OFFSET OF SYSTEM MEMORY
	   "RegBase"=dword:13E00000	; CS + 0x03E00000
	ENDIF
